<?php
declare(strict_types=1);

namespace Zlf\Mysql;

class Column
{
    /**
     * 表字段信息
     * @var array<array{'field':string,'type':string,'comment':string,'default':mixed,'null':'YES'|'No','null':'auto_increment'|mixed}>
     */
    protected array $column = [];

    /**
     * @param array<array{'field':string,'type':string,'comment':string,'default':mixed,'null':'YES'|'No','null':'auto_increment'|mixed}> $column
     */
    public function __construct(array $column)
    {
        $this->column = $column;
    }

    /**
     * @describe 获取数据表信息
     * @param array<array{'field':string,'type':string,'comment':string,'default':mixed,'null':'YES'|'No','null':'auto_increment'|mixed}> $column
     * @return void
     * @user zlf zms-pro@qq.com 2025/1/18
     */
    public static function info(array $column)
    {
        (new self($column))->getInfo();
    }

    public function getInfo()
    {
        $result = [];
        foreach ($this->column as $item) {
            $row = [
                'field' => $item['field'],//字段名称
                'type' => $this->getType($item['type']),//字段类型
                'analysis' => true,//是否解析成功
                'min' => 0,
                'max' => 0,
                'precision' => 0,
                'length' => 0,
            ];//字段
            switch ($row['type']) {
                case "int":
                case "tinyint":
                case "smallint":
                case "mediumint":
                case "bigint":
                    $row = array_merge($row, $this->getIntegerInfo($item));
                    break;
                case "float":
                case "double":
                case "decimal":
                    $row = array_merge($row, $this->getFloatInfo($item));
                    break;
                default:
                    print_r([
                        $item['type']
                    ]);
                    $row['analysis'] = false;
                    break;
            }
            $result[] = $row;
        }
    }


    /**
     * @describe 获取字段类型
     * @param string $type
     * @return string
     * @user zlf zms-pro@qq.com 2025/1/18
     */
    private function getType(string $type): string
    {
        $pos = strpos($type, '('); // 查找第一个左括号的位置
        if ($pos !== false) {
            return substr($type, 0, $pos); // 获取括号之前的部分
        }
        $pos2 = strpos($type, ' '); // 查找第一个左括号的位置
        if ($pos2 !== false) {
            return substr($type, 0, $pos2); // 获取括号之前的部分
        }
        return $type;
    }

    /**
     * @describe 解析INT字段
     * @param array{'field':string,'type':string,'comment':string,'default':mixed,'null':'YES'|'No','null':'auto_increment'|mixed} $find
     * @return array{max:numeric,min:numeric}
     * @user zlf zms-pro@qq.com 2025/1/18
     */
    private function getIntegerInfo(array $find): array
    {
        // 去除类型中的长度定义，如 INT(10) -> INT
        $type = preg_replace('/\(\d+\)/', '', $find['type']);
        // 定义MySQL数字类型的取值范围
        $ranges = [
            'tinyint' => ['signed' => ['min' => -128, 'max' => 127], 'unsigned' => ['min' => 0, 'max' => 255]],
            'smallint' => ['signed' => ['min' => -32768, 'max' => 32767], 'unsigned' => ['min' => 0, 'max' => 65535]],
            'mediumint' => ['signed' => ['min' => -8388608, 'max' => 8388607], 'unsigned' => ['min' => 0, 'max' => 16777215]],
            'int' => ['signed' => ['min' => -2147483648, 'max' => 2147483647], 'unsigned' => ['min' => 0, 'max' => 4294967295]],
            'bigint' => ['signed' => ['min' => -9223372036854775808, 'max' => 9223372036854775807], 'unsigned' => ['min' => 0, 'max' => 18446744073709551615]],
        ];

        // 检查是否为无符号类型
        $isUnsigned = str_contains($type, 'unsigned');
        $type = str_replace(' unsigned', '', $type);

        $range = $isUnsigned ? $ranges[$type]['unsigned'] : $ranges[$type]['signed'];

        $is_len = preg_match('/(\d+)/', $find['type'], $len);
        if (!$is_len) {
            return $range;
        }
        $value = (int)str_repeat('9', (int)$len[0]);
        return [
            'max' => max($range['max'], $value), 'min' => max($range['min'], 0 - $value)
        ];
    }

    /**
     * @describe 获取浮点类型取值范围,不好界定取值范围，只根据长度和精度给了个合理的取值范围
     * @param array $find
     * @return array{max:numeric,min:numeric,precision:int}
     * @user zlf zms-pro@qq.com 2025/1/18
     */
    private function getFloatInfo(array $find): array
    {
        $lenght = 11;
        $precision = 0;
        $isUnsigned = str_contains($find['type'], 'unsigned');
        if (in_array($find['type'], ['float', 'double', 'decimal'])) {
            if ($isUnsigned) {
                return [
                    'min' => 0, 'max' => 1000000000, 'precision' => $precision
                ];
            }
            return [
                'min' => -100000000, 'max' => 100000000, 'precision' => $precision
            ];
        }
        if (preg_match_all("/(\d+)/", $find['type'], $info)) {
            $lenght = (int)($info[0][0] ?? 10);
            $precision = (int)($info[0][1] ?? 0);
        }
        $value = (int)('1' . str_repeat('0', ($lenght - $precision - 1)));

        return [
            'min' => 0 - $value, 'max' => $value, 'precision' => $precision
        ];
    }
}